[React 05] styled component


Posted by tzutzu858 on 2021-04-26

React 有很多種方式可以寫 CSS

  1. inline-style,用 style={}
  2. HTML 的 CSS link ,引入外部 CSS
  3. 使用 webpack 打包
  4. styled component 它是一個套件,比較主流用法

官方文件至少 Basics看完,有一些基本用法

安裝

# with npm
npm install --save styled-components

# with yarn
yarn add styled-components

import

import styled from 'styled-components'

舉例 :

const Title = styled.h1` 
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

宣告 Title = styled.h1,h1 就是 h1 標籤,後面用反引號,反引號除了用在樣板字串(template strings)以外,還可以用在標籤模版(tagged template),參考文章 :[筆記] JavaScript ES6 中的模版字符串(template literals)和標籤模版(tagged template)


一樣可以傳 props 進去

例如 tag 裡面加 size = "XL"
接收 props 用 ${},裡面要放 function,通常用箭頭函式比較方便

const TodoButton = styled.div`
    color:rgba(2, 1, 23);
    font-size: ${props => props.size === 'XL' ? '20px' : '12px'}
`

不一定要用三元運算子,可以用短路邏輯

const TodoButton = styled.div`
    color:rgba(2, 1, 23);
    font-size: 12px;
    ${props => props.size === 'XL' && `
    font-size: 20px;
    `}
`

如果是 XL ,那 font-size: 12px; 就會被蓋過去


restyle

對 style component 做 restyle

const RedButton = styled(Button)`
    color: red;
`

如果是對一般的 component 進行 restyle,則需要在 component 傳入 className,用來接收class 屬性

// 繼承 TodoItem component,需要傳入 className
function TodoItem ({ className, size, content }) {
  return (
    <TodoItemWrapper className={className}>
      <TodoContent size={size}>{content}</TodoContent>
      <TodoButtonWrapper>
        <Button>未完成</Button>
        <GreenButton>刪除</GreenButton>
      </TodoButtonWrapper>
    </TodoItemWrapper>
  );
}
  // 繼承 TodoItem
  const BlackTodoItem = styled(TodoItem)`
    background: #000;
  `

function App() {
  const titleSize = "M"
  return (
    <div className="App">
      <TodoItem content={123} />
      <BlackTodoItem content={456} size="XL" />
    </div>
  );
}

@media

透過 Media Query 實作 RWD

const Button = styled.button`
  font-size: 20px;

  @media screen and (min-width: 768px) {
      font-size 16px;
  }

像 Media Query 重複率很高,所以可以額外開個資料夾像是 constants\style.js 檔案,以便重複使用

export const MEDIA_QUERY_MD = '@media screen and {min-width: 768px}'
export const MEDIA_QUERY_LG = '@media screen and {min-width: 1080px}'

便可以在其他檔案引入使用

import { MEDIA_QUERY_MD, MEDIA_QUERY_LG} from './constants/style';

const Button = styled.button`
  font-size: 20px;

  ${MEDIA_QUERY_MD} {
    font-size 16px;
  }

  ${MEDIA_QUERY_LG} {
    font-size: 12px;
  }
`

向量變數

Advanced Usage裡面有個Theming,可以傳個 Global 變數,使用向量變數

index.js 引入 ThemeProvider

import { ThemeProvider } from 'styled-components';

// 提供 theme 的參數
const theme = {
  colors: {
    primary_300: '#ff7777',
    primary_400: '#e33e3e',
    primary_500: '#af0505',
  }
}

ReactDOM.render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

App.js 中取用這些變數

const TodoContent = styled.div`
  font-size: 20px;
  color: ${props => props.theme.colors.primary_300};

  ${MEDIA_QUERY_MD} {
    font-size: 16px;
    color: ${props => props.theme.colors.primary_400};
  }

  ${MEDIA_QUERY_LG} {
    font-size: 12px;
    color: ${props => props.theme.colors.primary_500};
  }
`


component 越來越大可以獨立出去

export default function TodoItem() {...}

引入

import TodoItem from './TodoItem'









Related Posts

建立映像檔使用Dockerfile

建立映像檔使用Dockerfile

Secure Apache Using Certbot with Let's Encrypt on Ubuntu 20.04

Secure Apache Using Certbot with Let's Encrypt on Ubuntu 20.04

Vue3 XML Pretty Print與Theme呈現

Vue3 XML Pretty Print與Theme呈現


Comments